package com.ccrfid.rmc6.service.business.prison.patrolcheck;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.business.prison.patrolcheck.*;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.pojo.dto.prison.patrolcheck.PatrolCheckGroupDto;
import com.ccrfid.rmc6.pojo.dto.prison.patrolcheck.PatrolCheckResultDetailDto;
import com.ccrfid.rmc6.pojo.dto.prison.patrolcheck.PatrolCheckResultDto;
import com.ccrfid.rmc6.repository.business.prison.patrolcheck.*;
import com.ccrfid.rmc6.repository.search.SearchCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
public class PatrolCheckServiceImpl implements PatrolCheckService {
    private static final Logger logger = LoggerFactory.getLogger(PatrolCheckServiceImpl.class);

    @PersistenceContext
    private EntityManager entityManager;
    @Autowired
    private PatrolCheckGroupRepository patrolCheckGroupRepository;
    @Autowired
    private PatrolCheckPointRepository patrolCheckPointRepository;
    @Autowired
    private PatrolCheckPointViewRepository patrolCheckPointViewRepository;
    @Autowired
    private PatrolCheckResultRepository patrolCheckResultRepository;
    @Autowired
    private PatrolCheckResultDetailRepository patrolCheckResultDetailRepository;
    @Autowired
    private PatrolCheckPlanTimeRepository patrolCheckPlanTimeRepository;
    @Autowired
    private PatrolCheckPointPositionRepository patrolCheckPointPositionRepository;

    @Override
    public List<PatrolCheckPlanTimeEntity> getPatrolCheckPlanTimeList() {
        return patrolCheckPlanTimeRepository.getAllByOrderByPlanTimeAsc();
    }

    @Override
    public PatrolCheckPlanTimeEntity createPatrolCheckPlanTime(Time timeValue) {
        PatrolCheckPlanTimeEntity timeEntity = patrolCheckPlanTimeRepository.getByPlanTime(timeValue);
        if (timeEntity != null) {
            return timeEntity;
        } else {
            PatrolCheckPlanTimeEntity planTimeEntity = new PatrolCheckPlanTimeEntity();
            planTimeEntity.setPlanTime(timeValue);
            return patrolCheckPlanTimeRepository.save(planTimeEntity);
        }
    }

    @Override
    public Boolean deletePatrolCheckPlanTime(Time timeValue) {
        if (patrolCheckPlanTimeRepository.existsByPlanTime(timeValue)) {
            patrolCheckPlanTimeRepository.deleteAllByPlanTime(timeValue);
        }
        return true;
    }

    @Override
    public List<PatrolCheckGroupEntity> getAllPatrolCheckGroups() {
        return patrolCheckGroupRepository.getAllBy();
    }

    @Override
    public PatrolCheckGroupEntity getPatrolCheckGroup(Long groupId) {
        return patrolCheckGroupRepository.getById(groupId);
    }

    @Override
    public PatrolCheckGroupEntity createPatrolCheckGroup(PatrolCheckGroupEntity entity) throws AppException {
        checkParam(entity);
        return patrolCheckGroupRepository.save(entity);
    }

    private void checkParam(PatrolCheckGroupEntity entity) throws AppException {
        if (entity.getGroupName() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_group_name_is_null.getCode(), CustomErrors.check_group_name_is_null.getReason(), "");
        }
        if (entity.getNodeType() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.node_type_is_null.getCode(), CustomErrors.node_type_is_null.getReason(), "");
        }
        if (entity.getPid() != null) {
            PatrolCheckGroupEntity parentNode = patrolCheckGroupRepository.getById(entity.getPid());
            if (parentNode == null) {
                //1.父节点不存在
                throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                        CustomErrors.pid_not_found.getCode(), CustomErrors.pid_not_found.getReason(), "");
            } else {
                //2.父节点不是目录类型
                if (!parentNode.getNodeType().equals(Constants.NODE_TYPE.CATALOG.id)) {
                    throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                            CustomErrors.parent_node_not_catalog.getCode(), CustomErrors.parent_node_not_catalog.getReason(), "");
                }
            }
        }
    }

    @Override
    public PatrolCheckGroupEntity updatePatrolCheckGroup(Long groupId, PatrolCheckGroupEntity entity) throws AppException {
        if (!patrolCheckGroupRepository.existsById(groupId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (!groupId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }

        checkParam(entity);
        return patrolCheckGroupRepository.save(entity);
    }

    @Override
    public Boolean deletePatrolCheckGroup(Long groupId) {
        deleteNodeAndSubNodes(groupId);
        return true;
    }

    private void deleteNodeAndSubNodes(Long groupId) {
        if (patrolCheckGroupRepository.existsByPid(groupId)) {
            //1.删除子节点
            List<PatrolCheckGroupEntity> list = patrolCheckGroupRepository.getAllByPid(groupId);
            for (PatrolCheckGroupEntity groupEntity : list) {
                deleteNodeAndSubNodes(groupEntity.getId());
            }
            //2.删除自己
            deleteNode(groupId);
        } else {
            //删除自己
            deleteNode(groupId);
        }
    }

    private void deleteNode(Long groupId) {
        //1.删除相关巡更点
        if (patrolCheckPointRepository.existsByGroupId(groupId)) {
            patrolCheckPointRepository.deleteAllByGroupId(groupId);
        }
        //2.删除巡更组
        if (patrolCheckGroupRepository.existsById(groupId)) {
            patrolCheckGroupRepository.deleteById(groupId);
        }
    }

    @Override
    public List<PatrolCheckPointView> getPatrolCheckPointList(SearchCriteria criteria, Sort sort) {
        return patrolCheckPointViewRepository.search(criteria, sort);
    }

    @Override
    public PatrolCheckPointEntity createPatrolCheckPoint(Long groupId, PatrolCheckPointEntity entity) throws AppException {
        if (!patrolCheckGroupRepository.existsById(groupId)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_group_not_found.getCode(), CustomErrors.check_group_not_found.getReason(), "");
        }
        if (!groupId.equals(entity.getGroupId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        if (entity.getCardNumber() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_number_is_null.getCode(), CustomErrors.check_point_number_is_null.getReason(), "");
        }
        if (entity.getCheckPointName() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_name_is_null.getCode(), CustomErrors.check_point_name_is_null.getReason(), "");
        }
        //同一巡更组内，巡更点标签号不可重复
        if (patrolCheckPointRepository.existsByGroupIdAndCardNumber(groupId, entity.getCardNumber())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_card_number_conflict.getCode(), CustomErrors.check_point_card_number_conflict.getReason(), "");
        }
        PatrolCheckGroupEntity groupEntity = patrolCheckGroupRepository.getById(groupId);
        if (!Constants.NODE_TYPE.NODE.id.equals(groupEntity.getNodeType())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.parent_not_node_type.getCode(), CustomErrors.parent_not_node_type.getReason(), "");
        }
        return patrolCheckPointRepository.save(entity);
    }

    @Override
    public PatrolCheckPointEntity updatePatrolCheckPoint(Long groupId, Long checkPointId, PatrolCheckPointEntity entity)
            throws AppException {
        if (!patrolCheckGroupRepository.existsById(groupId)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_group_not_found.getCode(), CustomErrors.check_group_not_found.getReason(), "");
        }
        if (!patrolCheckPointRepository.existsById(checkPointId)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_not_found.getCode(), CustomErrors.check_point_not_found.getReason(), "");
        }
        if (!groupId.equals(entity.getGroupId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        if (!checkPointId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        if (entity.getCardNumber() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_number_is_null.getCode(), CustomErrors.check_point_number_is_null.getReason(), "");
        }
        if (entity.getCheckPointName() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_name_is_null.getCode(), CustomErrors.check_point_name_is_null.getReason(), "");
        }
        //同一巡更组内，巡更点标签号不可重复
        if (patrolCheckPointRepository.existsByGroupIdAndCardNumberAndIdNot(groupId, entity.getCardNumber(), checkPointId)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_card_number_conflict.getCode(), CustomErrors.check_point_card_number_conflict.getReason(), "");
        }
        PatrolCheckGroupEntity groupEntity = patrolCheckGroupRepository.getById(groupId);
        if (!Constants.NODE_TYPE.NODE.id.equals(groupEntity.getNodeType())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.parent_not_node_type.getCode(), CustomErrors.parent_not_node_type.getReason(), "");
        }
        return patrolCheckPointRepository.save(entity);
    }

    @Override
    public Boolean deletePatrolCheckPoint(Long groupId, Long checkPointId) {
        if (patrolCheckPointRepository.existsByGroupIdAndId(groupId, checkPointId)) {
            //删除位置信息
            if (patrolCheckPointPositionRepository.existsByCheckPointId(checkPointId)) {
                patrolCheckPointPositionRepository.deleteByCheckPointId(checkPointId);
            }
            //删除检查点信息
            patrolCheckPointRepository.deleteById(checkPointId);
        }
        return true;
    }

    @Override
    public Boolean deletePatrolCheckPoints(Long groupId, List<Long> checkPointIdList) {
        if (checkPointIdList != null && checkPointIdList.size() > 0) {
            for (Long checkPointId : checkPointIdList) {
                deletePatrolCheckPoint(groupId, checkPointId);
            }
        }
        return true;
    }

    @Override
    public Page<PatrolCheckResultEntity> getPatrolCheckResult(SearchCriteria criteria, Pageable pageable) {
        return patrolCheckResultRepository.search(criteria, pageable);
    }

    @Override
    public Page<PatrolCheckResultDetailEntity> getPatrolCheckResultDetails(SearchCriteria criteria, Pageable pageable) {
        return patrolCheckResultDetailRepository.search(criteria, pageable);
    }

    @Override
    public List<PatrolCheckGroupDto> getPatrolCheckGroupConfig() {
        List<PatrolCheckGroupDto> list = new ArrayList<>();
        List<PatrolCheckGroupEntity> groupEntityList = patrolCheckGroupRepository.getAllByNodeType(Constants.NODE_TYPE.NODE.id);
        if (groupEntityList != null && groupEntityList.size() > 0) {
            for (PatrolCheckGroupEntity groupEntity : groupEntityList) {
                PatrolCheckGroupDto groupDto = new PatrolCheckGroupDto();
                groupDto.setCheckGroup(groupEntity);
                groupDto.setCheckPointList(getPatrolCheckPointListOfGroup(groupEntity.getId()));
                list.add(groupDto);
            }
        }
        return list;
    }

    private List<PatrolCheckPointEntity> getPatrolCheckPointListOfGroup(Long groupId) {
        List<PatrolCheckPointEntity> list = patrolCheckPointRepository.getAllByGroupId(groupId);
        if (list != null) {
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public void updatePatrolCheckResultList(List<PatrolCheckResultDto> resultList) {
        for (PatrolCheckResultDto resultDto : resultList) {
            PatrolCheckResultEntity resultEntity = resultDto.getInfo();
            List<PatrolCheckResultDetailEntity> resultDetailEntityList = resultDto.getDetails();

            PatrolCheckResultEntity patrolCheckResultEntity =
                    patrolCheckResultRepository.getByPoliceIdAndGroupIdAndStartTimeAndStopTime(
                            resultEntity.getPoliceId(), resultEntity.getGroupId(),
                            resultEntity.getStartTime(), resultEntity.getStopTime());

            if (patrolCheckResultEntity != null) {
                //忽略重复提交
            } else {
                patrolCheckResultRepository.save(resultEntity);
                if (resultDetailEntityList != null && resultDetailEntityList.size() > 0) {
                    for (PatrolCheckResultDetailEntity resultDetailEntity : resultDetailEntityList) {
                        resultDetailEntity.setCheckResultId(resultEntity.getId());
                        patrolCheckResultDetailRepository.save(resultDetailEntity);
                    }
                }
            }
        }
    }

    @Override
    public List<PatrolCheckResultDetailDto> getPatrolCheckResultPathLine(Long checkResultId) {
        String sql = "select d.id, d.check_result_id, d.card_number, d.check_point_name, d.result_status, " +
                " d.patrol_check_time, d.remark, v.floor_number, v.position " +
                " from patrol_check_result_detail d " +
                " left join patrol_check_result r on d.check_result_id = r.id " +
                " left join v_patrol_check_point v on r.group_id = v.group_id and d.card_number = v.card_number " +
                " where d.check_result_id = :crId " +
                " order by d.patrol_check_time asc";
        List<PatrolCheckResultDetailDto> list = entityManager.createNativeQuery(sql, PatrolCheckResultDetailDto.class)
                .setParameter("crId", checkResultId)
                .getResultList();
        return list;
    }

    @Override
    public PatrolCheckPointView createPatrolCheckPointPosition(Long pointId,
                                                               PatrolCheckPointPositionEntity positionEntity)
            throws AppException {
        if (patrolCheckPointRepository.existsById(pointId)) {
            positionEntity.setCheckPointId(pointId);
            patrolCheckPointPositionRepository.save(positionEntity);

            PatrolCheckPointEntity pointEntity = patrolCheckPointRepository.getById(pointId);
            PatrolCheckPointView pointView = new PatrolCheckPointView();
            pointView.setId(pointId);
            pointView.setCardNumber(pointEntity.getCardNumber());
            pointView.setCheckPointName(pointEntity.getCheckPointName());
            pointView.setGroupId(pointEntity.getGroupId());
            pointView.setFloorNumber(positionEntity.getFloorNumber());
            pointView.setPosition(positionEntity.getPosition());
            return pointView;
        } else {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_not_found.getCode(), CustomErrors.check_point_not_found.getReason(), "");
        }
    }

    @Override
    public Boolean deletePatrolCheckPointPosition(Long pointId) throws AppException {
        if (patrolCheckPointRepository.existsById(pointId)) {
            if (patrolCheckPointPositionRepository.existsByCheckPointId(pointId)) {
                patrolCheckPointPositionRepository.deleteByCheckPointId(pointId);
            }
            return true;
        } else {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.check_point_not_found.getCode(), CustomErrors.check_point_not_found.getReason(), "");
        }
    }
}
